home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SPACE 2
/
SPACE - Library 2 - Volume 1.iso
/
telecom
/
86
/
pascal
/
nowwhat2.txt
< prev
next >
Wrap
Text File
|
1986-12-19
|
18KB
|
361 lines
Now What?
OSS Personal Pascal and the beginner - part 2
written by David Meile
[Copyright 1986 David Meile, all rights reserved. Permission is
given to Atari user groups to reprint this article, as long as
this statement is included. OSS Personal Pascal is a product of
Optimized Systems Software, Inc. I am not related to the company,
I simply bought their compiler.]
Windows, Graphics and Pascal
One of the many nice things about OSS Personal Pascal is that it
provides the Pascal programmer with simple access to many of the GEM
operating system features. Unfortunately, while access is simple,
it is not always EASY. GEM requires a lot of prompting before it will
produce something like a Window. But, once you get the basic idea
of how to access GEM from Pascal, it DOES become easier as you write
more programs.
Last time, I said I was going to draw some lines. Actually, I am
going to do a little more than that ... I am going to introduce the
basics of creating a Window to draw ON. The program that follows is
called GRAPHICS.PAS.
The program
PROGRAM graphics;
{ Clear the screen and draw something }
CONST
{$I gemconst.pas }
TYPE
{$I gemtype.pas }
VAR
x,y,w,h,
my_window : integer;
my_event : integer;
wind_type : integer;
title : Window_Title;
{ The following must be defined for completeness, but are not used }
message : Message_Buffer;
key : integer;
bcnt,bstate : integer;
mx,my : integer;
kbd_state : integer;
{$I gemsubs.pas }
PROCEDURE Do_Graph;
BEGIN
wind_type := G_Name;
title := ' Drawing a box ';
my_window := New_Window( wind_type, title, 0, 0, 0, 0 );
Hide_Mouse;
Open_Window( my_window, 0, 0, 0, 0 );
Set_Window( my_window );
Work_Rect( my_window, x, y, w, h );
Set_Clip( x, y, w, h );
Paint_Color( White );
Paint_Rect( 0, 0, w, h );
Line_Color( Black );
Text_Color( Black );
Draw_String( 10,10, 'You can draw text on screen too!');
Line( 15,15, 15,100 );
Line_To( 100,100 );
Line_To( 100,15 );
Line_To( 15,15 );
Line_To( 100,100 );
Line( 15,100, 100,15 );
Draw_String( 15,110, 'Click the left button to exit...');
my_event := Get_Event( E_Button, 1, 1, 1, 0,
False, 0, 0, 0, 0,
False, 0, 0, 0, 0,
message, key, bcnt, bstate, mx, my, kbd_state );
Close_Window( my_window );
Show_Mouse;
Delete_Window( my_window );
END;
BEGIN
IF Init_Gem >= 0 THEN
BEGIN
Do_Graph;
Exit_Gem;
END;
END.
And now ... the explanation
Quite a lot of things are going on in that little program, right?
I am sure that you recognize most of the lines at the very end. There
is the 'Init_Gem' function, asking GEM if it can create a new workspace.
There is the 'Exit_Gem' procedure, telling GEM that the program is
finished with the workspace. And there is that funny line that simply
says 'Do_Graph'.
But first, a brief digression
Pascal works best in small chunks of code, called PROCEDURES and
FUNCTIONS. As you may remember, a function is a subprogram that, when
called, returns a single value. The function 'Init_Gem' returns an
integer value greater or equal to zero when GEM can run the program.
A PROCEDURE is a subprogram that, when called, performs some sort
of action. It may (or may not) return one or more values. Procedures
can require PARAMETERS, which are variables with some sort of value.
'Draw_String' is a procedure in the program above. It's parameters
are two integer values and a string. (Remember, strings are enclosed
by single quota marks - 'This is a string'). 'Exit_Gem' is a procedure
with no parameters.
One of the advantages of Pascal over BASIC is that procedures and
functions can have variables that do not affect the program outside
of that particular subprogram. A short example:
Program example1;
VAR
a, b : integer;
Procedure dark( x : integer; y : integer );
VAR
a, b : integer;
BEGIN {Procedure dark}
a := x;
b := a * y;
Writeln( 'a = ', a , ' b = ', b );
END; {dark}
BEGIN {Main program example1}
a := 10;
b := 5;
dark( a, b );
Writeln( 'a = ', a, ' b = ', b );
END. {example 1}
What do you think this short program will do? Print out values
of 'a' and 'b' of course. First, assign 10 to a and 5 to b. Then
call the procedure dark. The two parameters are a and b ... they are
called x and y WITHIN procedure dark. Assign x to a (so a = 10) and
assign a * y to b (10 * 5 = 50, so b = 50). The Writeln will print
out the following:
a = 10 b = 50
Now, exit dark and go back to the main program. Here we print out
the values of a and b. But the values of a and b have not changed
in the main program, they only changed within procedure dark. So,
a is STILL 10 and b is STILL 5 in the main program. The Writeln will
print out the following:
a = 10 b = 5
If you have followed this, congratulations! You now know about LOCAL
(within a procedure) variables.
Now, back to the REAL program
OK. You can see that 'Do_Graph' is a procedure. There are no
parameters, so any variables included in Do_Graph must be GLOBAL ..
that is, the variables listed at the top of the program apply to the
procedure as well. A GLOBAL variable can be changed by ANY subprogram,
and should not be used much within your own programs. 'Proper' Pascal
programs almost always use LOCAL variables within procedures, passing
parameters back to the main program when necessary.
With that in mind, let's look at what's going on in the procedure
called Do_Graph. The first thing you can see are several assignments.
'wind_type' is an integer variable used in the function New_Window.
It can be made up of several parts, and describes the parts of the
GEM Window we want to be there. These include the scroll bars, the
"close window" box, and the window name. G_Name is an bit value
for the window name. G_Close is another bit value for the close
window box. When combined they produce an integer value that we can
assign to wind_type. To include both, you would type:
wind_type := G_Name | G_Close;
Additional parts of a GEM window can be included: G_Full, G_Move,
G_Info, etc.
Since I'm going to have a window name, I may as well tell GEM what
it is, right? That is the variable 'title'. You'll notice that the
variable is declared 'title : Window_Title'. Window_Title is a special
TYPE included in the GEMTYPE.PAS file. If you're interested, you can
look at GEMTYPE.PAS to see how "special" types are declared.
Having my two variables assigned, I make a call to the function
called 'New_Window'. You can tell it is a function because it's on the
right side of an assignment statement. The variable 'my_window' is
an integer, so the function New_Window returns an integer value. The
function New_Window asks GEM to set up space for a window, and lets
Pascal know how to access it by number. It also tells GEM what the
title for the window should be.
I don't want the mouse arrow to clutter up my nice graphics screen,
so I tell GEM to hide it with the procedure 'Hide_Mouse'. You MUST
include a 'Show_Mouse' somewhere in your program for every Hide_Mouse
you execute. If you don't, when your program is finished, GEM will
still be hiding the mouse when you get back to the Desktop ... not
a pretty 'sight'!
OK. The mouse is in hiding, and I can safely OPEN a new window,
using the procedure 'Open_Window' (of course). I tell GEM to open
the window it has reserved and to give me the maximum amount of space
to work with (the 0,0,0,0 tells GEM to make the window as BIG as possible,
which generally means full-screen. Don't exceed the values that you used
in the New_Window function call...). To make SURE that the window I
just opened is the one I will be using, I use the procedure 'Set_Window'.
If you have several windows open at once, you use Set_Window to tell
GEM which one you're going to be working with now. Notice that the
variable 'my_window' lets GEM know WHICH window I'm talking about.
The window is open and set. I want to find out how much space I
have to work with, so I use the procedure 'Work_Rect'. The variables
x,y,w, and h are given values by the procedure Work_Rect, and I can
use them in my program to determine several things. The x and y tell
me where the 'origin' of the window is, and w and h tell me how wide
and high the window is. This is useful information -- it means I don't
have to write separate procedures for each resolution mode (LOW, MEDIUM
and HIGH resolution). Instead, I can restrict myself to the boundaries
given by these values.
I can do better than that. I can tell GEM to ignore things I draw
that are outside the window boundaries by making a call to 'Set_Clip'.
This procedure will take the values I got from Work_Rect and tell GEM
not to do any actual drawing outside of those boundaries. Now, regardless
of how big or small my window is, I can draw on it without fear of
crashing the system by going outside of the window boundaries.
I have my window on screen, but it's got the background color of
the GEM Desktop. I much prefer to draw on a white background, so I
set the 'Paint_Color' to white and then tell GEM to paint the entire
window that color using 'Paint_Rect'. Notice that the width and height
are passed to Paint_Rect. I have set the origin at 0,0, which is the
upper left corner of the window (or it's supposed to be ... try it
using x,y instead of 0,0 and note the results).
OK, I have a white background, so I'm going to draw things with
black lines. I set 'Line_Color' and 'Text_Color' to black. Then I
call procedure 'Draw_String'. The two parameters are x and y pixel
values, x going horizontally and y going vertically. 10,10 is 10 pixels
to the right and 10 pixels down.
Next, I draw some lines. Ideally, I would be drawing a square,
with corners at 15,15 and 100,100. However, it may not look like it
on your screen. The reason for this is that there are MORE x pixels
than there are y pixels on your screen. In LOW resolution there are
320 x 200 pixels. In HIGH resolution there are 640 x 400 pixels.
In MEDIUM resolution there are 640 x 200 pixels. The first number
is the x pixel value, the second number is the y pixel value.
For now, we'll not worry about it. BUT, if you're going to be doing
lots of graphics, you'll want to set up some sort of "fudge-factor" to
make things look right. One possible solution is to multiply the x
value by some constant based on the resolution mode you are in. For
example, in MEDIUM resolution, multiplying x by 3.2 would compensate.
(3.2 x 200 = 640.)
There are two procedures for drawing lines: 'Line' and 'Line_To'.
The first requires two endpoints, the beginning of the line and the
end of the line. The second requires one endpoint, using the end of
the last line as the beginning of the new line.
My lines are drawn, and all of the text is also drawn. The second
Draw_String is an absolute MUST. The reason? You should ALWAYS let
the person using your program know what to do next! If the second
line were omitted, I would have no idea that I was supposed to press
the left mouse button to exit the program. It is good programming
practice to include such 'hints' where they are needed.
How do I tell when the left button is pressed? I use the Pascal
function 'Get_Event'. There are a LOT of parameters for this function.
Some are not needed just to test for a simple click on the left mouse
button. These are duly noted in the VAR declaration part of the program.
'my_event' is an integer value returned by Get_Event. In many cases,
your program would take this value and continue to do something else.
Here, it simply sets up the program to await a click of the 'ol mouse
button.
Get_Event parameters needed to test the mouse button include
E_Button ("I'm waiting for a mouse button event..."), and several values
that follow. The first '1' means "left mouse button", the second '1'
means "waiting for user to click button", the third '1' means "wait for
one click" and the '0' means "wait this long for the button click". In
this case, that '0' is meaningless (as are the 'False' and other '0's in
the parameter list) since we are not using the E_Timer event flag.
Everything else is simply there for completeness.
Once I click the mouse, I close the window I created with
'Close_Window'. Then I 'Show_Mouse', because I hid it earlier and
I want to SEE the mouse arrow once my program is finished! Then I
'Delete_Window', which releases the space GEM has allocated for my
window since I no longer need it.
Done at last. Look at all of that work, simply to draw a couple of
lines on the screen! However, the next time I want to create a window
and draw some lines, it'll be that much easier...
Of RAM disks and Pascal programming
If you have a 1040 ST, or a 520 ST with a 1 megabyte memory upgrade,
you can move the OSS Personal Pascal files from disk to a RAM disk.
This makes things like calling the compiler and linker MUCH faster.
You need to make sure that the RAM disk you are using can survive a
computer RESET. Talk to your local Atari ST user group to see if they
have a copy of one of the many RAM disks available. One such is called
ETERNAL.PRG, another is available in an archive file called YARD.ARC.
To automate moving your Pascal program files to the RAM disk, you
need to look for a program such as FLDR2DSK.PRG, also available from many
bulletin boards and user groups. I use this program, but do not put it
into the AUTO folder as the instructions mention. The reason is that
my RAM disk is created on a number of disks, and there is no real reason
to reboot my system simply to load OSS Personal Pascal.
If you own an Atari 520 ST without the memory upgrade, you can speed
things up somewhat by using a RAM disk and putting your programs on the
RAM disk instead of Pascal. There are some instructions available to do
this, which should be available from your local user group. If you can't
find them, I will be happy to copy them for the cost of a STAMPED self-
addressed envelope. About the best you can hope for is a 200k RAM disk.
Wrapping things up
I'd like to thank everybody who sent me letters and E-Mail regarding
the first column. In future months, you can expect to see some more
articles on working with OSS Personal Pascal.
In next month's article, I will discuss reading from and saving to
files. I'll also talk about using the pre-defined DIALOG boxes that
are accessible from OSS Personal Pascal.
I'm open to answering some SIMPLE questions regarding
Personal Pascal. You can reach me via GEnie as D.MEILE, or
write (include a stamp, please) to:
David Meile
Box 13038 - Dinkytown Station
Minneapolis, MN 55414
Additional reading
If you are interested in a college text for Pascal, you might find
that AN INTRODUCTION TO PROGRAMMING AND PROBLEM SOLVING WITH PASCAL by
G. Michael Schneider, Steven W. Weingart and David M. Perlman is useful.
It is published by John Wiley and Sons, and the latest version was
published in (I believe) 1984. It was the text used for beginning
programming classes at the University of Minnesota in Minneapolis when
I learned to program in Pascal.